/*
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.dx.rop.code;

import com.android.dx.rop.cst.Constant;
import com.android.dx.rop.cst.CstBaseMethodRef;
import com.android.dx.rop.cst.CstMethodRef;
import com.android.dx.rop.cst.CstType;
import com.android.dx.rop.type.Prototype;
import com.android.dx.rop.type.StdTypeList;
import com.android.dx.rop.type.Type;
import com.android.dx.rop.type.TypeBearer;
import com.android.dx.rop.type.TypeList;

/**
 * Standard instances of {@link Rop}.
 */
public final class Rops {

	/** {@code nop()} */
	public static final Rop NOP = new Rop(RegOps.NOP, Type.VOID,
			StdTypeList.EMPTY, "nop");

	/** {@code r,x: int :: r = x;} */
	public static final Rop MOVE_INT = new Rop(RegOps.MOVE, Type.INT,
			StdTypeList.INT, "move-int");

	/** {@code r,x: long :: r = x;} */
	public static final Rop MOVE_LONG = new Rop(RegOps.MOVE, Type.LONG,
			StdTypeList.LONG, "move-long");

	/** {@code r,x: float :: r = x;} */
	public static final Rop MOVE_FLOAT = new Rop(RegOps.MOVE, Type.FLOAT,
			StdTypeList.FLOAT, "move-float");

	/** {@code r,x: double :: r = x;} */
	public static final Rop MOVE_DOUBLE = new Rop(RegOps.MOVE, Type.DOUBLE,
			StdTypeList.DOUBLE, "move-double");

	/** {@code r,x: Object :: r = x;} */
	public static final Rop MOVE_OBJECT = new Rop(RegOps.MOVE, Type.OBJECT,
			StdTypeList.OBJECT, "move-object");

	/**
	 * {@code r,x: ReturnAddress :: r = x;} Note that this rop-form instruction
	 * has no dex-form equivilent and must be removed before the dex conversion.
	 */
	public static final Rop MOVE_RETURN_ADDRESS = new Rop(RegOps.MOVE,
			Type.RETURN_ADDRESS, StdTypeList.RETURN_ADDRESS,
			"move-return-address");

	/** {@code r,param(x): int :: r = param(x);} */
	public static final Rop MOVE_PARAM_INT = new Rop(RegOps.MOVE_PARAM,
			Type.INT, StdTypeList.EMPTY, "move-param-int");

	/** {@code r,param(x): long :: r = param(x);} */
	public static final Rop MOVE_PARAM_LONG = new Rop(RegOps.MOVE_PARAM,
			Type.LONG, StdTypeList.EMPTY, "move-param-long");

	/** {@code r,param(x): float :: r = param(x);} */
	public static final Rop MOVE_PARAM_FLOAT = new Rop(RegOps.MOVE_PARAM,
			Type.FLOAT, StdTypeList.EMPTY, "move-param-float");

	/** {@code r,param(x): double :: r = param(x);} */
	public static final Rop MOVE_PARAM_DOUBLE = new Rop(RegOps.MOVE_PARAM,
			Type.DOUBLE, StdTypeList.EMPTY, "move-param-double");

	/** {@code r,param(x): Object :: r = param(x);} */
	public static final Rop MOVE_PARAM_OBJECT = new Rop(RegOps.MOVE_PARAM,
			Type.OBJECT, StdTypeList.EMPTY, "move-param-object");

	/** {@code r, literal: int :: r = literal;} */
	public static final Rop CONST_INT = new Rop(RegOps.CONST, Type.INT,
			StdTypeList.EMPTY, "const-int");

	/** {@code r, literal: long :: r = literal;} */
	public static final Rop CONST_LONG = new Rop(RegOps.CONST, Type.LONG,
			StdTypeList.EMPTY, "const-long");

	/** {@code r, literal: float :: r = literal;} */
	public static final Rop CONST_FLOAT = new Rop(RegOps.CONST, Type.FLOAT,
			StdTypeList.EMPTY, "const-float");

	/** {@code r, literal: double :: r = literal;} */
	public static final Rop CONST_DOUBLE = new Rop(RegOps.CONST, Type.DOUBLE,
			StdTypeList.EMPTY, "const-double");

	/** {@code r, literal: Object :: r = literal;} */
	public static final Rop CONST_OBJECT = new Rop(RegOps.CONST, Type.OBJECT,
			StdTypeList.EMPTY, Exceptions.LIST_Error, "const-object");

	/** {@code r, literal: Object :: r = literal;} */
	public static final Rop CONST_OBJECT_NOTHROW = new Rop(RegOps.CONST,
			Type.OBJECT, StdTypeList.EMPTY, "const-object-nothrow");

	/** {@code goto label} */
	public static final Rop GOTO = new Rop(RegOps.GOTO, Type.VOID,
			StdTypeList.EMPTY, Rop.BRANCH_GOTO, "goto");

	/** {@code x: int :: if (x == 0) goto label} */
	public static final Rop IF_EQZ_INT = new Rop(RegOps.IF_EQ, Type.VOID,
			StdTypeList.INT, Rop.BRANCH_IF, "if-eqz-int");

	/** {@code x: int :: if (x != 0) goto label} */
	public static final Rop IF_NEZ_INT = new Rop(RegOps.IF_NE, Type.VOID,
			StdTypeList.INT, Rop.BRANCH_IF, "if-nez-int");

	/** {@code x: int :: if (x < 0) goto label} */
	public static final Rop IF_LTZ_INT = new Rop(RegOps.IF_LT, Type.VOID,
			StdTypeList.INT, Rop.BRANCH_IF, "if-ltz-int");

	/** {@code x: int :: if (x >= 0) goto label} */
	public static final Rop IF_GEZ_INT = new Rop(RegOps.IF_GE, Type.VOID,
			StdTypeList.INT, Rop.BRANCH_IF, "if-gez-int");

	/** {@code x: int :: if (x <= 0) goto label} */
	public static final Rop IF_LEZ_INT = new Rop(RegOps.IF_LE, Type.VOID,
			StdTypeList.INT, Rop.BRANCH_IF, "if-lez-int");

	/** {@code x: int :: if (x > 0) goto label} */
	public static final Rop IF_GTZ_INT = new Rop(RegOps.IF_GT, Type.VOID,
			StdTypeList.INT, Rop.BRANCH_IF, "if-gtz-int");

	/** {@code x: Object :: if (x == null) goto label} */
	public static final Rop IF_EQZ_OBJECT = new Rop(RegOps.IF_EQ, Type.VOID,
			StdTypeList.OBJECT, Rop.BRANCH_IF, "if-eqz-object");

	/** {@code x: Object :: if (x != null) goto label} */
	public static final Rop IF_NEZ_OBJECT = new Rop(RegOps.IF_NE, Type.VOID,
			StdTypeList.OBJECT, Rop.BRANCH_IF, "if-nez-object");

	/** {@code x,y: int :: if (x == y) goto label} */
	public static final Rop IF_EQ_INT = new Rop(RegOps.IF_EQ, Type.VOID,
			StdTypeList.INT_INT, Rop.BRANCH_IF, "if-eq-int");

	/** {@code x,y: int :: if (x != y) goto label} */
	public static final Rop IF_NE_INT = new Rop(RegOps.IF_NE, Type.VOID,
			StdTypeList.INT_INT, Rop.BRANCH_IF, "if-ne-int");

	/** {@code x,y: int :: if (x < y) goto label} */
	public static final Rop IF_LT_INT = new Rop(RegOps.IF_LT, Type.VOID,
			StdTypeList.INT_INT, Rop.BRANCH_IF, "if-lt-int");

	/** {@code x,y: int :: if (x >= y) goto label} */
	public static final Rop IF_GE_INT = new Rop(RegOps.IF_GE, Type.VOID,
			StdTypeList.INT_INT, Rop.BRANCH_IF, "if-ge-int");

	/** {@code x,y: int :: if (x <= y) goto label} */
	public static final Rop IF_LE_INT = new Rop(RegOps.IF_LE, Type.VOID,
			StdTypeList.INT_INT, Rop.BRANCH_IF, "if-le-int");

	/** {@code x,y: int :: if (x > y) goto label} */
	public static final Rop IF_GT_INT = new Rop(RegOps.IF_GT, Type.VOID,
			StdTypeList.INT_INT, Rop.BRANCH_IF, "if-gt-int");

	/** {@code x,y: Object :: if (x == y) goto label} */
	public static final Rop IF_EQ_OBJECT = new Rop(RegOps.IF_EQ, Type.VOID,
			StdTypeList.OBJECT_OBJECT, Rop.BRANCH_IF, "if-eq-object");

	/** {@code x,y: Object :: if (x != y) goto label} */
	public static final Rop IF_NE_OBJECT = new Rop(RegOps.IF_NE, Type.VOID,
			StdTypeList.OBJECT_OBJECT, Rop.BRANCH_IF, "if-ne-object");

	/** {@code x: int :: goto switchtable[x]} */
	public static final Rop SWITCH = new Rop(RegOps.SWITCH, Type.VOID,
			StdTypeList.INT, Rop.BRANCH_SWITCH, "switch");

	/** {@code r,x,y: int :: r = x + y;} */
	public static final Rop ADD_INT = new Rop(RegOps.ADD, Type.INT,
			StdTypeList.INT_INT, "add-int");

	/** {@code r,x,y: long :: r = x + y;} */
	public static final Rop ADD_LONG = new Rop(RegOps.ADD, Type.LONG,
			StdTypeList.LONG_LONG, "add-long");

	/** {@code r,x,y: float :: r = x + y;} */
	public static final Rop ADD_FLOAT = new Rop(RegOps.ADD, Type.FLOAT,
			StdTypeList.FLOAT_FLOAT, "add-float");

	/** {@code r,x,y: double :: r = x + y;} */
	public static final Rop ADD_DOUBLE = new Rop(RegOps.ADD, Type.DOUBLE,
			StdTypeList.DOUBLE_DOUBLE, Rop.BRANCH_NONE, "add-double");

	/** {@code r,x,y: int :: r = x - y;} */
	public static final Rop SUB_INT = new Rop(RegOps.SUB, Type.INT,
			StdTypeList.INT_INT, "sub-int");

	/** {@code r,x,y: long :: r = x - y;} */
	public static final Rop SUB_LONG = new Rop(RegOps.SUB, Type.LONG,
			StdTypeList.LONG_LONG, "sub-long");

	/** {@code r,x,y: float :: r = x - y;} */
	public static final Rop SUB_FLOAT = new Rop(RegOps.SUB, Type.FLOAT,
			StdTypeList.FLOAT_FLOAT, "sub-float");

	/** {@code r,x,y: double :: r = x - y;} */
	public static final Rop SUB_DOUBLE = new Rop(RegOps.SUB, Type.DOUBLE,
			StdTypeList.DOUBLE_DOUBLE, Rop.BRANCH_NONE, "sub-double");

	/** {@code r,x,y: int :: r = x * y;} */
	public static final Rop MUL_INT = new Rop(RegOps.MUL, Type.INT,
			StdTypeList.INT_INT, "mul-int");

	/** {@code r,x,y: long :: r = x * y;} */
	public static final Rop MUL_LONG = new Rop(RegOps.MUL, Type.LONG,
			StdTypeList.LONG_LONG, "mul-long");

	/** {@code r,x,y: float :: r = x * y;} */
	public static final Rop MUL_FLOAT = new Rop(RegOps.MUL, Type.FLOAT,
			StdTypeList.FLOAT_FLOAT, "mul-float");

	/** {@code r,x,y: double :: r = x * y;} */
	public static final Rop MUL_DOUBLE = new Rop(RegOps.MUL, Type.DOUBLE,
			StdTypeList.DOUBLE_DOUBLE, Rop.BRANCH_NONE, "mul-double");

	/** {@code r,x,y: int :: r = x / y;} */
	public static final Rop DIV_INT = new Rop(RegOps.DIV, Type.INT,
			StdTypeList.INT_INT, Exceptions.LIST_Error_ArithmeticException,
			"div-int");

	/** {@code r,x,y: long :: r = x / y;} */
	public static final Rop DIV_LONG = new Rop(RegOps.DIV, Type.LONG,
			StdTypeList.LONG_LONG, Exceptions.LIST_Error_ArithmeticException,
			"div-long");

	/** {@code r,x,y: float :: r = x / y;} */
	public static final Rop DIV_FLOAT = new Rop(RegOps.DIV, Type.FLOAT,
			StdTypeList.FLOAT_FLOAT, "div-float");

	/** {@code r,x,y: double :: r = x / y;} */
	public static final Rop DIV_DOUBLE = new Rop(RegOps.DIV, Type.DOUBLE,
			StdTypeList.DOUBLE_DOUBLE, "div-double");

	/** {@code r,x,y: int :: r = x % y;} */
	public static final Rop REM_INT = new Rop(RegOps.REM, Type.INT,
			StdTypeList.INT_INT, Exceptions.LIST_Error_ArithmeticException,
			"rem-int");

	/** {@code r,x,y: long :: r = x % y;} */
	public static final Rop REM_LONG = new Rop(RegOps.REM, Type.LONG,
			StdTypeList.LONG_LONG, Exceptions.LIST_Error_ArithmeticException,
			"rem-long");

	/** {@code r,x,y: float :: r = x % y;} */
	public static final Rop REM_FLOAT = new Rop(RegOps.REM, Type.FLOAT,
			StdTypeList.FLOAT_FLOAT, "rem-float");

	/** {@code r,x,y: double :: r = x % y;} */
	public static final Rop REM_DOUBLE = new Rop(RegOps.REM, Type.DOUBLE,
			StdTypeList.DOUBLE_DOUBLE, "rem-double");

	/** {@code r,x: int :: r = -x;} */
	public static final Rop NEG_INT = new Rop(RegOps.NEG, Type.INT,
			StdTypeList.INT, "neg-int");

	/** {@code r,x: long :: r = -x;} */
	public static final Rop NEG_LONG = new Rop(RegOps.NEG, Type.LONG,
			StdTypeList.LONG, "neg-long");

	/** {@code r,x: float :: r = -x;} */
	public static final Rop NEG_FLOAT = new Rop(RegOps.NEG, Type.FLOAT,
			StdTypeList.FLOAT, "neg-float");

	/** {@code r,x: double :: r = -x;} */
	public static final Rop NEG_DOUBLE = new Rop(RegOps.NEG, Type.DOUBLE,
			StdTypeList.DOUBLE, "neg-double");

	/** {@code r,x,y: int :: r = x & y;} */
	public static final Rop AND_INT = new Rop(RegOps.AND, Type.INT,
			StdTypeList.INT_INT, "and-int");

	/** {@code r,x,y: long :: r = x & y;} */
	public static final Rop AND_LONG = new Rop(RegOps.AND, Type.LONG,
			StdTypeList.LONG_LONG, "and-long");

	/** {@code r,x,y: int :: r = x | y;} */
	public static final Rop OR_INT = new Rop(RegOps.OR, Type.INT,
			StdTypeList.INT_INT, "or-int");

	/** {@code r,x,y: long :: r = x | y;} */
	public static final Rop OR_LONG = new Rop(RegOps.OR, Type.LONG,
			StdTypeList.LONG_LONG, "or-long");

	/** {@code r,x,y: int :: r = x ^ y;} */
	public static final Rop XOR_INT = new Rop(RegOps.XOR, Type.INT,
			StdTypeList.INT_INT, "xor-int");

	/** {@code r,x,y: long :: r = x ^ y;} */
	public static final Rop XOR_LONG = new Rop(RegOps.XOR, Type.LONG,
			StdTypeList.LONG_LONG, "xor-long");

	/** {@code r,x,y: int :: r = x << y;} */
	public static final Rop SHL_INT = new Rop(RegOps.SHL, Type.INT,
			StdTypeList.INT_INT, "shl-int");

	/** {@code r,x: long; y: int :: r = x << y;} */
	public static final Rop SHL_LONG = new Rop(RegOps.SHL, Type.LONG,
			StdTypeList.LONG_INT, "shl-long");

	/** {@code r,x,y: int :: r = x >> y;} */
	public static final Rop SHR_INT = new Rop(RegOps.SHR, Type.INT,
			StdTypeList.INT_INT, "shr-int");

	/** {@code r,x: long; y: int :: r = x >> y;} */
	public static final Rop SHR_LONG = new Rop(RegOps.SHR, Type.LONG,
			StdTypeList.LONG_INT, "shr-long");

	/** {@code r,x,y: int :: r = x >>> y;} */
	public static final Rop USHR_INT = new Rop(RegOps.USHR, Type.INT,
			StdTypeList.INT_INT, "ushr-int");

	/** {@code r,x: long; y: int :: r = x >>> y;} */
	public static final Rop USHR_LONG = new Rop(RegOps.USHR, Type.LONG,
			StdTypeList.LONG_INT, "ushr-long");

	/** {@code r,x: int :: r = ~x;} */
	public static final Rop NOT_INT = new Rop(RegOps.NOT, Type.INT,
			StdTypeList.INT, "not-int");

	/** {@code r,x: long :: r = ~x;} */
	public static final Rop NOT_LONG = new Rop(RegOps.NOT, Type.LONG,
			StdTypeList.LONG, "not-long");

	/** {@code r,x,c: int :: r = x + c;} */
	public static final Rop ADD_CONST_INT = new Rop(RegOps.ADD, Type.INT,
			StdTypeList.INT, "add-const-int");

	/** {@code r,x,c: long :: r = x + c;} */
	public static final Rop ADD_CONST_LONG = new Rop(RegOps.ADD, Type.LONG,
			StdTypeList.LONG, "add-const-long");

	/** {@code r,x,c: float :: r = x + c;} */
	public static final Rop ADD_CONST_FLOAT = new Rop(RegOps.ADD, Type.FLOAT,
			StdTypeList.FLOAT, "add-const-float");

	/** {@code r,x,c: double :: r = x + c;} */
	public static final Rop ADD_CONST_DOUBLE = new Rop(RegOps.ADD, Type.DOUBLE,
			StdTypeList.DOUBLE, "add-const-double");

	/** {@code r,x,c: int :: r = x - c;} */
	public static final Rop SUB_CONST_INT = new Rop(RegOps.SUB, Type.INT,
			StdTypeList.INT, "sub-const-int");

	/** {@code r,x,c: long :: r = x - c;} */
	public static final Rop SUB_CONST_LONG = new Rop(RegOps.SUB, Type.LONG,
			StdTypeList.LONG, "sub-const-long");

	/** {@code r,x,c: float :: r = x - c;} */
	public static final Rop SUB_CONST_FLOAT = new Rop(RegOps.SUB, Type.FLOAT,
			StdTypeList.FLOAT, "sub-const-float");

	/** {@code r,x,c: double :: r = x - c;} */
	public static final Rop SUB_CONST_DOUBLE = new Rop(RegOps.SUB, Type.DOUBLE,
			StdTypeList.DOUBLE, "sub-const-double");

	/** {@code r,x,c: int :: r = x * c;} */
	public static final Rop MUL_CONST_INT = new Rop(RegOps.MUL, Type.INT,
			StdTypeList.INT, "mul-const-int");

	/** {@code r,x,c: long :: r = x * c;} */
	public static final Rop MUL_CONST_LONG = new Rop(RegOps.MUL, Type.LONG,
			StdTypeList.LONG, "mul-const-long");

	/** {@code r,x,c: float :: r = x * c;} */
	public static final Rop MUL_CONST_FLOAT = new Rop(RegOps.MUL, Type.FLOAT,
			StdTypeList.FLOAT, "mul-const-float");

	/** {@code r,x,c: double :: r = x * c;} */
	public static final Rop MUL_CONST_DOUBLE = new Rop(RegOps.MUL, Type.DOUBLE,
			StdTypeList.DOUBLE, "mul-const-double");

	/** {@code r,x,c: int :: r = x / c;} */
	public static final Rop DIV_CONST_INT = new Rop(RegOps.DIV, Type.INT,
			StdTypeList.INT, Exceptions.LIST_Error_ArithmeticException,
			"div-const-int");

	/** {@code r,x,c: long :: r = x / c;} */
	public static final Rop DIV_CONST_LONG = new Rop(RegOps.DIV, Type.LONG,
			StdTypeList.LONG, Exceptions.LIST_Error_ArithmeticException,
			"div-const-long");

	/** {@code r,x,c: float :: r = x / c;} */
	public static final Rop DIV_CONST_FLOAT = new Rop(RegOps.DIV, Type.FLOAT,
			StdTypeList.FLOAT, "div-const-float");

	/** {@code r,x,c: double :: r = x / c;} */
	public static final Rop DIV_CONST_DOUBLE = new Rop(RegOps.DIV, Type.DOUBLE,
			StdTypeList.DOUBLE, "div-const-double");

	/** {@code r,x,c: int :: r = x % c;} */
	public static final Rop REM_CONST_INT = new Rop(RegOps.REM, Type.INT,
			StdTypeList.INT, Exceptions.LIST_Error_ArithmeticException,
			"rem-const-int");

	/** {@code r,x,c: long :: r = x % c;} */
	public static final Rop REM_CONST_LONG = new Rop(RegOps.REM, Type.LONG,
			StdTypeList.LONG, Exceptions.LIST_Error_ArithmeticException,
			"rem-const-long");

	/** {@code r,x,c: float :: r = x % c;} */
	public static final Rop REM_CONST_FLOAT = new Rop(RegOps.REM, Type.FLOAT,
			StdTypeList.FLOAT, "rem-const-float");

	/** {@code r,x,c: double :: r = x % c;} */
	public static final Rop REM_CONST_DOUBLE = new Rop(RegOps.REM, Type.DOUBLE,
			StdTypeList.DOUBLE, "rem-const-double");

	/** {@code r,x,c: int :: r = x & c;} */
	public static final Rop AND_CONST_INT = new Rop(RegOps.AND, Type.INT,
			StdTypeList.INT, "and-const-int");

	/** {@code r,x,c: long :: r = x & c;} */
	public static final Rop AND_CONST_LONG = new Rop(RegOps.AND, Type.LONG,
			StdTypeList.LONG, "and-const-long");

	/** {@code r,x,c: int :: r = x | c;} */
	public static final Rop OR_CONST_INT = new Rop(RegOps.OR, Type.INT,
			StdTypeList.INT, "or-const-int");

	/** {@code r,x,c: long :: r = x | c;} */
	public static final Rop OR_CONST_LONG = new Rop(RegOps.OR, Type.LONG,
			StdTypeList.LONG, "or-const-long");

	/** {@code r,x,c: int :: r = x ^ c;} */
	public static final Rop XOR_CONST_INT = new Rop(RegOps.XOR, Type.INT,
			StdTypeList.INT, "xor-const-int");

	/** {@code r,x,c: long :: r = x ^ c;} */
	public static final Rop XOR_CONST_LONG = new Rop(RegOps.XOR, Type.LONG,
			StdTypeList.LONG, "xor-const-long");

	/** {@code r,x,c: int :: r = x << c;} */
	public static final Rop SHL_CONST_INT = new Rop(RegOps.SHL, Type.INT,
			StdTypeList.INT, "shl-const-int");

	/** {@code r,x: long; c: int :: r = x << c;} */
	public static final Rop SHL_CONST_LONG = new Rop(RegOps.SHL, Type.LONG,
			StdTypeList.INT, "shl-const-long");

	/** {@code r,x,c: int :: r = x >> c;} */
	public static final Rop SHR_CONST_INT = new Rop(RegOps.SHR, Type.INT,
			StdTypeList.INT, "shr-const-int");

	/** {@code r,x: long; c: int :: r = x >> c;} */
	public static final Rop SHR_CONST_LONG = new Rop(RegOps.SHR, Type.LONG,
			StdTypeList.INT, "shr-const-long");

	/** {@code r,x,c: int :: r = x >>> c;} */
	public static final Rop USHR_CONST_INT = new Rop(RegOps.USHR, Type.INT,
			StdTypeList.INT, "ushr-const-int");

	/** {@code r,x: long; c: int :: r = x >>> c;} */
	public static final Rop USHR_CONST_LONG = new Rop(RegOps.USHR, Type.LONG,
			StdTypeList.INT, "ushr-const-long");

	/** {@code r: int; x,y: long :: r = cmp(x, y);} */
	public static final Rop CMPL_LONG = new Rop(RegOps.CMPL, Type.INT,
			StdTypeList.LONG_LONG, "cmpl-long");

	/** {@code r: int; x,y: float :: r = cmpl(x, y);} */
	public static final Rop CMPL_FLOAT = new Rop(RegOps.CMPL, Type.INT,
			StdTypeList.FLOAT_FLOAT, "cmpl-float");

	/** {@code r: int; x,y: double :: r = cmpl(x, y);} */
	public static final Rop CMPL_DOUBLE = new Rop(RegOps.CMPL, Type.INT,
			StdTypeList.DOUBLE_DOUBLE, "cmpl-double");

	/** {@code r: int; x,y: float :: r = cmpg(x, y);} */
	public static final Rop CMPG_FLOAT = new Rop(RegOps.CMPG, Type.INT,
			StdTypeList.FLOAT_FLOAT, "cmpg-float");

	/** {@code r: int; x,y: double :: r = cmpg(x, y);} */
	public static final Rop CMPG_DOUBLE = new Rop(RegOps.CMPG, Type.INT,
			StdTypeList.DOUBLE_DOUBLE, "cmpg-double");

	/** {@code r: int; x: long :: r = (int) x} */
	public static final Rop CONV_L2I = new Rop(RegOps.CONV, Type.INT,
			StdTypeList.LONG, "conv-l2i");

	/** {@code r: int; x: float :: r = (int) x} */
	public static final Rop CONV_F2I = new Rop(RegOps.CONV, Type.INT,
			StdTypeList.FLOAT, "conv-f2i");

	/** {@code r: int; x: double :: r = (int) x} */
	public static final Rop CONV_D2I = new Rop(RegOps.CONV, Type.INT,
			StdTypeList.DOUBLE, "conv-d2i");

	/** {@code r: long; x: int :: r = (long) x} */
	public static final Rop CONV_I2L = new Rop(RegOps.CONV, Type.LONG,
			StdTypeList.INT, "conv-i2l");

	/** {@code r: long; x: float :: r = (long) x} */
	public static final Rop CONV_F2L = new Rop(RegOps.CONV, Type.LONG,
			StdTypeList.FLOAT, "conv-f2l");

	/** {@code r: long; x: double :: r = (long) x} */
	public static final Rop CONV_D2L = new Rop(RegOps.CONV, Type.LONG,
			StdTypeList.DOUBLE, "conv-d2l");

	/** {@code r: float; x: int :: r = (float) x} */
	public static final Rop CONV_I2F = new Rop(RegOps.CONV, Type.FLOAT,
			StdTypeList.INT, "conv-i2f");

	/** {@code r: float; x: long :: r = (float) x} */
	public static final Rop CONV_L2F = new Rop(RegOps.CONV, Type.FLOAT,
			StdTypeList.LONG, "conv-l2f");

	/** {@code r: float; x: double :: r = (float) x} */
	public static final Rop CONV_D2F = new Rop(RegOps.CONV, Type.FLOAT,
			StdTypeList.DOUBLE, "conv-d2f");

	/** {@code r: double; x: int :: r = (double) x} */
	public static final Rop CONV_I2D = new Rop(RegOps.CONV, Type.DOUBLE,
			StdTypeList.INT, "conv-i2d");

	/** {@code r: double; x: long :: r = (double) x} */
	public static final Rop CONV_L2D = new Rop(RegOps.CONV, Type.DOUBLE,
			StdTypeList.LONG, "conv-l2d");

	/** {@code r: double; x: float :: r = (double) x} */
	public static final Rop CONV_F2D = new Rop(RegOps.CONV, Type.DOUBLE,
			StdTypeList.FLOAT, "conv-f2d");

	/**
	 * {@code r,x: int :: r = (x << 24) >> 24} (Java-style convert int to byte)
	 */
	public static final Rop TO_BYTE = new Rop(RegOps.TO_BYTE, Type.INT,
			StdTypeList.INT, "to-byte");

	/**
	 * {@code r,x: int :: r = x & 0xffff} (Java-style convert int to char)
	 */
	public static final Rop TO_CHAR = new Rop(RegOps.TO_CHAR, Type.INT,
			StdTypeList.INT, "to-char");

	/**
	 * {@code r,x: int :: r = (x << 16) >> 16} (Java-style convert int to short)
	 */
	public static final Rop TO_SHORT = new Rop(RegOps.TO_SHORT, Type.INT,
			StdTypeList.INT, "to-short");

	/** {@code return void} */
	public static final Rop RETURN_VOID = new Rop(RegOps.RETURN, Type.VOID,
			StdTypeList.EMPTY, Rop.BRANCH_RETURN, "return-void");

	/** {@code x: int; return x} */
	public static final Rop RETURN_INT = new Rop(RegOps.RETURN, Type.VOID,
			StdTypeList.INT, Rop.BRANCH_RETURN, "return-int");

	/** {@code x: long; return x} */
	public static final Rop RETURN_LONG = new Rop(RegOps.RETURN, Type.VOID,
			StdTypeList.LONG, Rop.BRANCH_RETURN, "return-long");

	/** {@code x: float; return x} */
	public static final Rop RETURN_FLOAT = new Rop(RegOps.RETURN, Type.VOID,
			StdTypeList.FLOAT, Rop.BRANCH_RETURN, "return-float");

	/** {@code x: double; return x} */
	public static final Rop RETURN_DOUBLE = new Rop(RegOps.RETURN, Type.VOID,
			StdTypeList.DOUBLE, Rop.BRANCH_RETURN, "return-double");

	/** {@code x: Object; return x} */
	public static final Rop RETURN_OBJECT = new Rop(RegOps.RETURN, Type.VOID,
			StdTypeList.OBJECT, Rop.BRANCH_RETURN, "return-object");

	/** {@code T: any type; r: int; x: T[]; :: r = x.length} */
	public static final Rop ARRAY_LENGTH = new Rop(RegOps.ARRAY_LENGTH,
			Type.INT, StdTypeList.OBJECT,
			Exceptions.LIST_Error_NullPointerException, "array-length");

	/** {@code x: Throwable :: throw(x)} */
	public static final Rop THROW = new Rop(RegOps.THROW, Type.VOID,
			StdTypeList.THROWABLE, StdTypeList.THROWABLE, "throw");

	/** {@code x: Object :: monitorenter(x)} */
	public static final Rop MONITOR_ENTER = new Rop(RegOps.MONITOR_ENTER,
			Type.VOID, StdTypeList.OBJECT,
			Exceptions.LIST_Error_NullPointerException, "monitor-enter");

	/** {@code x: Object :: monitorexit(x)} */
	public static final Rop MONITOR_EXIT = new Rop(RegOps.MONITOR_EXIT,
			Type.VOID, StdTypeList.OBJECT,
			Exceptions.LIST_Error_Null_IllegalMonitorStateException,
			"monitor-exit");

	/** {@code r,y: int; x: int[] :: r = x[y]} */
	public static final Rop AGET_INT = new Rop(RegOps.AGET, Type.INT,
			StdTypeList.INTARR_INT,
			Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aget-int");

	/** {@code r: long; x: long[]; y: int :: r = x[y]} */
	public static final Rop AGET_LONG = new Rop(RegOps.AGET, Type.LONG,
			StdTypeList.LONGARR_INT,
			Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aget-long");

	/** {@code r: float; x: float[]; y: int :: r = x[y]} */
	public static final Rop AGET_FLOAT = new Rop(RegOps.AGET, Type.FLOAT,
			StdTypeList.FLOATARR_INT,
			Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aget-float");

	/** {@code r: double; x: double[]; y: int :: r = x[y]} */
	public static final Rop AGET_DOUBLE = new Rop(RegOps.AGET, Type.DOUBLE,
			StdTypeList.DOUBLEARR_INT,
			Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aget-double");

	/** {@code r: Object; x: Object[]; y: int :: r = x[y]} */
	public static final Rop AGET_OBJECT = new Rop(RegOps.AGET, Type.OBJECT,
			StdTypeList.OBJECTARR_INT,
			Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aget-object");

	/** {@code r: boolean; x: boolean[]; y: int :: r = x[y]} */
	public static final Rop AGET_BOOLEAN = new Rop(RegOps.AGET, Type.INT,
			StdTypeList.BOOLEANARR_INT,
			Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aget-boolean");

	/** {@code r: byte; x: byte[]; y: int :: r = x[y]} */
	public static final Rop AGET_BYTE = new Rop(RegOps.AGET, Type.INT,
			StdTypeList.BYTEARR_INT,
			Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aget-byte");

	/** {@code r: char; x: char[]; y: int :: r = x[y]} */
	public static final Rop AGET_CHAR = new Rop(RegOps.AGET, Type.INT,
			StdTypeList.CHARARR_INT,
			Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aget-char");

	/** {@code r: short; x: short[]; y: int :: r = x[y]} */
	public static final Rop AGET_SHORT = new Rop(RegOps.AGET, Type.INT,
			StdTypeList.SHORTARR_INT,
			Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aget-short");

	/** {@code x,z: int; y: int[] :: y[z] = x} */
	public static final Rop APUT_INT = new Rop(RegOps.APUT, Type.VOID,
			StdTypeList.INT_INTARR_INT,
			Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aput-int");

	/** {@code x: long; y: long[]; z: int :: y[z] = x} */
	public static final Rop APUT_LONG = new Rop(RegOps.APUT, Type.VOID,
			StdTypeList.LONG_LONGARR_INT,
			Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aput-long");

	/** {@code x: float; y: float[]; z: int :: y[z] = x} */
	public static final Rop APUT_FLOAT = new Rop(RegOps.APUT, Type.VOID,
			StdTypeList.FLOAT_FLOATARR_INT,
			Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aput-float");

	/** {@code x: double; y: double[]; z: int :: y[z] = x} */
	public static final Rop APUT_DOUBLE = new Rop(RegOps.APUT, Type.VOID,
			StdTypeList.DOUBLE_DOUBLEARR_INT,
			Exceptions.LIST_Error_Null_ArrayIndexOutOfBounds, "aput-double");

	/** {@code x: Object; y: Object[]; z: int :: y[z] = x} */
	public static final Rop APUT_OBJECT = new Rop(RegOps.APUT, Type.VOID,
			StdTypeList.OBJECT_OBJECTARR_INT,
			Exceptions.LIST_Error_Null_ArrayIndex_ArrayStore, "aput-object");

	/** {@code x: boolean; y: boolean[]; z: int :: y[z] = x} */
	public static final Rop APUT_BOOLEAN = new Rop(RegOps.APUT, Type.VOID,
			StdTypeList.INT_BOOLEANARR_INT,
			Exceptions.LIST_Error_Null_ArrayIndex_ArrayStore, "aput-boolean");

	/** {@code x: byte; y: byte[]; z: int :: y[z] = x} */
	public static final Rop APUT_BYTE = new Rop(RegOps.APUT, Type.VOID,
			StdTypeList.INT_BYTEARR_INT,
			Exceptions.LIST_Error_Null_ArrayIndex_ArrayStore, "aput-byte");

	/** {@code x: char; y: char[]; z: int :: y[z] = x} */
	public static final Rop APUT_CHAR = new Rop(RegOps.APUT, Type.VOID,
			StdTypeList.INT_CHARARR_INT,
			Exceptions.LIST_Error_Null_ArrayIndex_ArrayStore, "aput-char");

	/** {@code x: short; y: short[]; z: int :: y[z] = x} */
	public static final Rop APUT_SHORT = new Rop(RegOps.APUT, Type.VOID,
			StdTypeList.INT_SHORTARR_INT,
			Exceptions.LIST_Error_Null_ArrayIndex_ArrayStore, "aput-short");

	/**
	 * {@code T: any non-array object type :: r =
	 * alloc(T)} (allocate heap space for an object)
	 */
	public static final Rop NEW_INSTANCE = new Rop(RegOps.NEW_INSTANCE,
			Type.OBJECT, StdTypeList.EMPTY, Exceptions.LIST_Error,
			"new-instance");

	/** {@code r: int[]; x: int :: r = new int[x]} */
	public static final Rop NEW_ARRAY_INT = new Rop(RegOps.NEW_ARRAY,
			Type.INT_ARRAY, StdTypeList.INT,
			Exceptions.LIST_Error_NegativeArraySizeException, "new-array-int");

	/** {@code r: long[]; x: int :: r = new long[x]} */
	public static final Rop NEW_ARRAY_LONG = new Rop(RegOps.NEW_ARRAY,
			Type.LONG_ARRAY, StdTypeList.INT,
			Exceptions.LIST_Error_NegativeArraySizeException, "new-array-long");

	/** {@code r: float[]; x: int :: r = new float[x]} */
	public static final Rop NEW_ARRAY_FLOAT = new Rop(RegOps.NEW_ARRAY,
			Type.FLOAT_ARRAY, StdTypeList.INT,
			Exceptions.LIST_Error_NegativeArraySizeException, "new-array-float");

	/** {@code r: double[]; x: int :: r = new double[x]} */
	public static final Rop NEW_ARRAY_DOUBLE = new Rop(RegOps.NEW_ARRAY,
			Type.DOUBLE_ARRAY, StdTypeList.INT,
			Exceptions.LIST_Error_NegativeArraySizeException,
			"new-array-double");

	/** {@code r: boolean[]; x: int :: r = new boolean[x]} */
	public static final Rop NEW_ARRAY_BOOLEAN = new Rop(RegOps.NEW_ARRAY,
			Type.BOOLEAN_ARRAY, StdTypeList.INT,
			Exceptions.LIST_Error_NegativeArraySizeException,
			"new-array-boolean");

	/** {@code r: byte[]; x: int :: r = new byte[x]} */
	public static final Rop NEW_ARRAY_BYTE = new Rop(RegOps.NEW_ARRAY,
			Type.BYTE_ARRAY, StdTypeList.INT,
			Exceptions.LIST_Error_NegativeArraySizeException, "new-array-byte");

	/** {@code r: char[]; x: int :: r = new char[x]} */
	public static final Rop NEW_ARRAY_CHAR = new Rop(RegOps.NEW_ARRAY,
			Type.CHAR_ARRAY, StdTypeList.INT,
			Exceptions.LIST_Error_NegativeArraySizeException, "new-array-char");

	/** {@code r: short[]; x: int :: r = new short[x]} */
	public static final Rop NEW_ARRAY_SHORT = new Rop(RegOps.NEW_ARRAY,
			Type.SHORT_ARRAY, StdTypeList.INT,
			Exceptions.LIST_Error_NegativeArraySizeException, "new-array-short");

	/**
	 * {@code T: any non-array object type; x: Object :: (T) x} (can throw
	 * {@code ClassCastException})
	 */
	public static final Rop CHECK_CAST = new Rop(RegOps.CHECK_CAST, Type.VOID,
			StdTypeList.OBJECT, Exceptions.LIST_Error_ClassCastException,
			"check-cast");

	/**
	 * {@code T: any non-array object type; x: Object :: x instanceof
	 * T}. Note: This is listed as throwing {@code Error} explicitly because the
	 * op <i>can</i> throw, but there are no other predefined exceptions for it.
	 */
	public static final Rop INSTANCE_OF = new Rop(RegOps.INSTANCE_OF, Type.INT,
			StdTypeList.OBJECT, Exceptions.LIST_Error, "instance-of");

	/**
	 * {@code r: int; x: Object; f: instance field spec of
	 * type int :: r = x.f}
	 */
	public static final Rop GET_FIELD_INT = new Rop(RegOps.GET_FIELD, Type.INT,
			StdTypeList.OBJECT, Exceptions.LIST_Error_NullPointerException,
			"get-field-int");

	/**
	 * {@code r: long; x: Object; f: instance field spec of
	 * type long :: r = x.f}
	 */
	public static final Rop GET_FIELD_LONG = new Rop(RegOps.GET_FIELD,
			Type.LONG, StdTypeList.OBJECT,
			Exceptions.LIST_Error_NullPointerException, "get-field-long");

	/**
	 * {@code r: float; x: Object; f: instance field spec of
	 * type float :: r = x.f}
	 */
	public static final Rop GET_FIELD_FLOAT = new Rop(RegOps.GET_FIELD,
			Type.FLOAT, StdTypeList.OBJECT,
			Exceptions.LIST_Error_NullPointerException, "get-field-float");

	/**
	 * {@code r: double; x: Object; f: instance field spec of
	 * type double :: r = x.f}
	 */
	public static final Rop GET_FIELD_DOUBLE = new Rop(RegOps.GET_FIELD,
			Type.DOUBLE, StdTypeList.OBJECT,
			Exceptions.LIST_Error_NullPointerException, "get-field-double");

	/**
	 * {@code r: Object; x: Object; f: instance field spec of
	 * type Object :: r = x.f}
	 */
	public static final Rop GET_FIELD_OBJECT = new Rop(RegOps.GET_FIELD,
			Type.OBJECT, StdTypeList.OBJECT,
			Exceptions.LIST_Error_NullPointerException, "get-field-object");

	/**
	 * {@code r: boolean; x: Object; f: instance field spec of
	 * type boolean :: r = x.f}
	 */
	public static final Rop GET_FIELD_BOOLEAN = new Rop(RegOps.GET_FIELD,
			Type.INT, StdTypeList.OBJECT,
			Exceptions.LIST_Error_NullPointerException, "get-field-boolean");

	/**
	 * {@code r: byte; x: Object; f: instance field spec of
	 * type byte :: r = x.f}
	 */
	public static final Rop GET_FIELD_BYTE = new Rop(RegOps.GET_FIELD,
			Type.INT, StdTypeList.OBJECT,
			Exceptions.LIST_Error_NullPointerException, "get-field-byte");

	/**
	 * {@code r: char; x: Object; f: instance field spec of
	 * type char :: r = x.f}
	 */
	public static final Rop GET_FIELD_CHAR = new Rop(RegOps.GET_FIELD,
			Type.INT, StdTypeList.OBJECT,
			Exceptions.LIST_Error_NullPointerException, "get-field-char");

	/**
	 * {@code r: short; x: Object; f: instance field spec of
	 * type short :: r = x.f}
	 */
	public static final Rop GET_FIELD_SHORT = new Rop(RegOps.GET_FIELD,
			Type.INT, StdTypeList.OBJECT,
			Exceptions.LIST_Error_NullPointerException, "get-field-short");

	/** {@code r: int; f: static field spec of type int :: r = f} */
	public static final Rop GET_STATIC_INT = new Rop(RegOps.GET_STATIC,
			Type.INT, StdTypeList.EMPTY, Exceptions.LIST_Error,
			"get-static-int");

	/** {@code r: long; f: static field spec of type long :: r = f} */
	public static final Rop GET_STATIC_LONG = new Rop(RegOps.GET_STATIC,
			Type.LONG, StdTypeList.EMPTY, Exceptions.LIST_Error,
			"get-static-long");

	/** {@code r: float; f: static field spec of type float :: r = f} */
	public static final Rop GET_STATIC_FLOAT = new Rop(RegOps.GET_STATIC,
			Type.FLOAT, StdTypeList.EMPTY, Exceptions.LIST_Error,
			"get-static-float");

	/** {@code r: double; f: static field spec of type double :: r = f} */
	public static final Rop GET_STATIC_DOUBLE = new Rop(RegOps.GET_STATIC,
			Type.DOUBLE, StdTypeList.EMPTY, Exceptions.LIST_Error,
			"get-static-double");

	/** {@code r: Object; f: static field spec of type Object :: r = f} */
	public static final Rop GET_STATIC_OBJECT = new Rop(RegOps.GET_STATIC,
			Type.OBJECT, StdTypeList.EMPTY, Exceptions.LIST_Error,
			"get-static-object");

	/** {@code r: boolean; f: static field spec of type boolean :: r = f} */
	public static final Rop GET_STATIC_BOOLEAN = new Rop(RegOps.GET_STATIC,
			Type.INT, StdTypeList.EMPTY, Exceptions.LIST_Error,
			"get-field-boolean");

	/** {@code r: byte; f: static field spec of type byte :: r = f} */
	public static final Rop GET_STATIC_BYTE = new Rop(RegOps.GET_STATIC,
			Type.INT, StdTypeList.EMPTY, Exceptions.LIST_Error,
			"get-field-byte");

	/** {@code r: char; f: static field spec of type char :: r = f} */
	public static final Rop GET_STATIC_CHAR = new Rop(RegOps.GET_STATIC,
			Type.INT, StdTypeList.EMPTY, Exceptions.LIST_Error,
			"get-field-char");

	/** {@code r: short; f: static field spec of type short :: r = f} */
	public static final Rop GET_STATIC_SHORT = new Rop(RegOps.GET_STATIC,
			Type.INT, StdTypeList.EMPTY, Exceptions.LIST_Error,
			"get-field-short");

	/**
	 * {@code x: int; y: Object; f: instance field spec of type
	 * int :: y.f = x}
	 */
	public static final Rop PUT_FIELD_INT = new Rop(RegOps.PUT_FIELD,
			Type.VOID, StdTypeList.INT_OBJECT,
			Exceptions.LIST_Error_NullPointerException, "put-field-int");

	/**
	 * {@code x: long; y: Object; f: instance field spec of type
	 * long :: y.f = x}
	 */
	public static final Rop PUT_FIELD_LONG = new Rop(RegOps.PUT_FIELD,
			Type.VOID, StdTypeList.LONG_OBJECT,
			Exceptions.LIST_Error_NullPointerException, "put-field-long");

	/**
	 * {@code x: float; y: Object; f: instance field spec of type
	 * float :: y.f = x}
	 */
	public static final Rop PUT_FIELD_FLOAT = new Rop(RegOps.PUT_FIELD,
			Type.VOID, StdTypeList.FLOAT_OBJECT,
			Exceptions.LIST_Error_NullPointerException, "put-field-float");

	/**
	 * {@code x: double; y: Object; f: instance field spec of type
	 * double :: y.f = x}
	 */
	public static final Rop PUT_FIELD_DOUBLE = new Rop(RegOps.PUT_FIELD,
			Type.VOID, StdTypeList.DOUBLE_OBJECT,
			Exceptions.LIST_Error_NullPointerException, "put-field-double");

	/**
	 * {@code x: Object; y: Object; f: instance field spec of type
	 * Object :: y.f = x}
	 */
	public static final Rop PUT_FIELD_OBJECT = new Rop(RegOps.PUT_FIELD,
			Type.VOID, StdTypeList.OBJECT_OBJECT,
			Exceptions.LIST_Error_NullPointerException, "put-field-object");

	/**
	 * {@code x: int; y: Object; f: instance field spec of type
	 * boolean :: y.f = x}
	 */
	public static final Rop PUT_FIELD_BOOLEAN = new Rop(RegOps.PUT_FIELD,
			Type.VOID, StdTypeList.INT_OBJECT,
			Exceptions.LIST_Error_NullPointerException, "put-field-boolean");

	/**
	 * {@code x: int; y: Object; f: instance field spec of type
	 * byte :: y.f = x}
	 */
	public static final Rop PUT_FIELD_BYTE = new Rop(RegOps.PUT_FIELD,
			Type.VOID, StdTypeList.INT_OBJECT,
			Exceptions.LIST_Error_NullPointerException, "put-field-byte");

	/**
	 * {@code x: int; y: Object; f: instance field spec of type
	 * char :: y.f = x}
	 */
	public static final Rop PUT_FIELD_CHAR = new Rop(RegOps.PUT_FIELD,
			Type.VOID, StdTypeList.INT_OBJECT,
			Exceptions.LIST_Error_NullPointerException, "put-field-char");

	/**
	 * {@code x: int; y: Object; f: instance field spec of type
	 * short :: y.f = x}
	 */
	public static final Rop PUT_FIELD_SHORT = new Rop(RegOps.PUT_FIELD,
			Type.VOID, StdTypeList.INT_OBJECT,
			Exceptions.LIST_Error_NullPointerException, "put-field-short");

	/** {@code f: static field spec of type int; x: int :: f = x} */
	public static final Rop PUT_STATIC_INT = new Rop(RegOps.PUT_STATIC,
			Type.VOID, StdTypeList.INT, Exceptions.LIST_Error, "put-static-int");

	/** {@code f: static field spec of type long; x: long :: f = x} */
	public static final Rop PUT_STATIC_LONG = new Rop(RegOps.PUT_STATIC,
			Type.VOID, StdTypeList.LONG, Exceptions.LIST_Error,
			"put-static-long");

	/** {@code f: static field spec of type float; x: float :: f = x} */
	public static final Rop PUT_STATIC_FLOAT = new Rop(RegOps.PUT_STATIC,
			Type.VOID, StdTypeList.FLOAT, Exceptions.LIST_Error,
			"put-static-float");

	/** {@code f: static field spec of type double; x: double :: f = x} */
	public static final Rop PUT_STATIC_DOUBLE = new Rop(RegOps.PUT_STATIC,
			Type.VOID, StdTypeList.DOUBLE, Exceptions.LIST_Error,
			"put-static-double");

	/** {@code f: static field spec of type Object; x: Object :: f = x} */
	public static final Rop PUT_STATIC_OBJECT = new Rop(RegOps.PUT_STATIC,
			Type.VOID, StdTypeList.OBJECT, Exceptions.LIST_Error,
			"put-static-object");

	/**
	 * {@code f: static field spec of type boolean; x: boolean :: f =
	 * x}
	 */
	public static final Rop PUT_STATIC_BOOLEAN = new Rop(RegOps.PUT_STATIC,
			Type.VOID, StdTypeList.INT, Exceptions.LIST_Error,
			"put-static-boolean");

	/** {@code f: static field spec of type byte; x: byte :: f = x} */
	public static final Rop PUT_STATIC_BYTE = new Rop(RegOps.PUT_STATIC,
			Type.VOID, StdTypeList.INT, Exceptions.LIST_Error,
			"put-static-byte");

	/** {@code f: static field spec of type char; x: char :: f = x} */
	public static final Rop PUT_STATIC_CHAR = new Rop(RegOps.PUT_STATIC,
			Type.VOID, StdTypeList.INT, Exceptions.LIST_Error,
			"put-static-char");

	/** {@code f: static field spec of type short; x: short :: f = x} */
	public static final Rop PUT_STATIC_SHORT = new Rop(RegOps.PUT_STATIC,
			Type.VOID, StdTypeList.INT, Exceptions.LIST_Error,
			"put-static-short");

	/** {@code x: Int :: local variable begins in x} */
	public static final Rop MARK_LOCAL_INT = new Rop(RegOps.MARK_LOCAL,
			Type.VOID, StdTypeList.INT, "mark-local-int");

	/** {@code x: Long :: local variable begins in x} */
	public static final Rop MARK_LOCAL_LONG = new Rop(RegOps.MARK_LOCAL,
			Type.VOID, StdTypeList.LONG, "mark-local-long");

	/** {@code x: Float :: local variable begins in x} */
	public static final Rop MARK_LOCAL_FLOAT = new Rop(RegOps.MARK_LOCAL,
			Type.VOID, StdTypeList.FLOAT, "mark-local-float");

	/** {@code x: Double :: local variable begins in x} */
	public static final Rop MARK_LOCAL_DOUBLE = new Rop(RegOps.MARK_LOCAL,
			Type.VOID, StdTypeList.DOUBLE, "mark-local-double");

	/** {@code x: Object :: local variable begins in x} */
	public static final Rop MARK_LOCAL_OBJECT = new Rop(RegOps.MARK_LOCAL,
			Type.VOID, StdTypeList.OBJECT, "mark-local-object");

	/** {@code T: Any primitive type; v0..vx: T :: v0, ..., vx} */
	public static final Rop FILL_ARRAY_DATA = new Rop(RegOps.FILL_ARRAY_DATA,
			Type.VOID, StdTypeList.EMPTY, "fill-array-data");

	/**
	 * Returns the appropriate rop for the given opcode, destination, and
	 * sources. The result is typically, but not necessarily, a shared instance.
	 * <p>
	 * <b>Note:</b> This method does not do complete error checking on its
	 * arguments, and so it may return an instance which seemed "right enough"
	 * even though in actuality the passed arguments don't quite match what is
	 * returned. TODO: Revisit this issue.
	 * </p>
	 * 
	 * @param opcode
	 *            the opcode
	 * @param dest
	 *            {@code non-null;} destination (result) type, or
	 *            {@link Type#VOID} if none
	 * @param sources
	 *            {@code non-null;} list of source types
	 * @param cst
	 *            {@code null-ok;} associated constant, if any
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop ropFor(int opcode, TypeBearer dest, TypeList sources,
			Constant cst) {
		switch (opcode) {
		case RegOps.NOP:
			return NOP;
		case RegOps.MOVE:
			return opMove(dest);
		case RegOps.MOVE_PARAM:
			return opMoveParam(dest);
		case RegOps.MOVE_EXCEPTION:
			return opMoveException(dest);
		case RegOps.CONST:
			return opConst(dest);
		case RegOps.GOTO:
			return GOTO;
		case RegOps.IF_EQ:
			return opIfEq(sources);
		case RegOps.IF_NE:
			return opIfNe(sources);
		case RegOps.IF_LT:
			return opIfLt(sources);
		case RegOps.IF_GE:
			return opIfGe(sources);
		case RegOps.IF_LE:
			return opIfLe(sources);
		case RegOps.IF_GT:
			return opIfGt(sources);
		case RegOps.SWITCH:
			return SWITCH;
		case RegOps.ADD:
			return opAdd(sources);
		case RegOps.SUB:
			return opSub(sources);
		case RegOps.MUL:
			return opMul(sources);
		case RegOps.DIV:
			return opDiv(sources);
		case RegOps.REM:
			return opRem(sources);
		case RegOps.NEG:
			return opNeg(dest);
		case RegOps.AND:
			return opAnd(sources);
		case RegOps.OR:
			return opOr(sources);
		case RegOps.XOR:
			return opXor(sources);
		case RegOps.SHL:
			return opShl(sources);
		case RegOps.SHR:
			return opShr(sources);
		case RegOps.USHR:
			return opUshr(sources);
		case RegOps.NOT:
			return opNot(dest);
		case RegOps.CMPL:
			return opCmpl(sources.getType(0));
		case RegOps.CMPG:
			return opCmpg(sources.getType(0));
		case RegOps.CONV:
			return opConv(dest, sources.getType(0));
		case RegOps.TO_BYTE:
			return TO_BYTE;
		case RegOps.TO_CHAR:
			return TO_CHAR;
		case RegOps.TO_SHORT:
			return TO_SHORT;
		case RegOps.RETURN: {
			if (sources.size() == 0) {
				return RETURN_VOID;
			}
			return opReturn(sources.getType(0));
		}
		case RegOps.ARRAY_LENGTH:
			return ARRAY_LENGTH;
		case RegOps.THROW:
			return THROW;
		case RegOps.MONITOR_ENTER:
			return MONITOR_ENTER;
		case RegOps.MONITOR_EXIT:
			return MONITOR_EXIT;
		case RegOps.AGET: {
			Type source = sources.getType(0);
			Type componentType;
			if (source == Type.KNOWN_NULL) {
				/*
				 * Treat a known-null as an array of the expected result type.
				 */
				componentType = dest.getType();
			} else {
				componentType = source.getComponentType();
			}
			return opAget(componentType);
		}
		case RegOps.APUT: {
			Type source = sources.getType(1);
			Type componentType;
			if (source == Type.KNOWN_NULL) {
				/*
				 * Treat a known-null as an array of the type being stored.
				 */
				componentType = sources.getType(0);
			} else {
				componentType = source.getComponentType();
			}
			return opAput(componentType);
		}
		case RegOps.NEW_INSTANCE:
			return NEW_INSTANCE;
		case RegOps.NEW_ARRAY:
			return opNewArray(dest.getType());
		case RegOps.CHECK_CAST:
			return CHECK_CAST;
		case RegOps.INSTANCE_OF:
			return INSTANCE_OF;
		case RegOps.GET_FIELD:
			return opGetField(dest);
		case RegOps.GET_STATIC:
			return opGetStatic(dest);
		case RegOps.PUT_FIELD:
			return opPutField(sources.getType(0));
		case RegOps.PUT_STATIC:
			return opPutStatic(sources.getType(0));
		case RegOps.INVOKE_STATIC: {
			return opInvokeStatic(((CstMethodRef) cst).getPrototype());
		}
		case RegOps.INVOKE_VIRTUAL: {
			CstBaseMethodRef cstMeth = (CstMethodRef) cst;
			Prototype meth = cstMeth.getPrototype();
			CstType definer = cstMeth.getDefiningClass();
			meth = meth.withFirstParameter(definer.getClassType());
			return opInvokeVirtual(meth);
		}
		case RegOps.INVOKE_SUPER: {
			CstBaseMethodRef cstMeth = (CstMethodRef) cst;
			Prototype meth = cstMeth.getPrototype();
			CstType definer = cstMeth.getDefiningClass();
			meth = meth.withFirstParameter(definer.getClassType());
			return opInvokeSuper(meth);
		}
		case RegOps.INVOKE_DIRECT: {
			CstBaseMethodRef cstMeth = (CstMethodRef) cst;
			Prototype meth = cstMeth.getPrototype();
			CstType definer = cstMeth.getDefiningClass();
			meth = meth.withFirstParameter(definer.getClassType());
			return opInvokeDirect(meth);
		}
		case RegOps.INVOKE_INTERFACE: {
			CstBaseMethodRef cstMeth = (CstMethodRef) cst;
			Prototype meth = cstMeth.getPrototype();
			CstType definer = cstMeth.getDefiningClass();
			meth = meth.withFirstParameter(definer.getClassType());
			return opInvokeInterface(meth);
		}
		}

		throw new RuntimeException("unknown opcode " + RegOps.opName(opcode));
	}

	/**
	 * Returns the appropriate {@code move} rop for the given type. The result
	 * is a shared instance.
	 * 
	 * @param type
	 *            {@code non-null;} type of value being moved
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opMove(TypeBearer type) {
		switch (type.getBasicFrameType()) {
		case Type.BT_INT:
			return MOVE_INT;
		case Type.BT_LONG:
			return MOVE_LONG;
		case Type.BT_FLOAT:
			return MOVE_FLOAT;
		case Type.BT_DOUBLE:
			return MOVE_DOUBLE;
		case Type.BT_OBJECT:
			return MOVE_OBJECT;
		case Type.BT_ADDR:
			return MOVE_RETURN_ADDRESS;
		}

		return throwBadType(type);
	}

	/**
	 * Returns the appropriate {@code move-param} rop for the given type. The
	 * result is a shared instance.
	 * 
	 * @param type
	 *            {@code non-null;} type of value being moved
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opMoveParam(TypeBearer type) {
		switch (type.getBasicFrameType()) {
		case Type.BT_INT:
			return MOVE_PARAM_INT;
		case Type.BT_LONG:
			return MOVE_PARAM_LONG;
		case Type.BT_FLOAT:
			return MOVE_PARAM_FLOAT;
		case Type.BT_DOUBLE:
			return MOVE_PARAM_DOUBLE;
		case Type.BT_OBJECT:
			return MOVE_PARAM_OBJECT;
		}

		return throwBadType(type);
	}

	/**
	 * Returns the appropriate {@code move-exception} rop for the given type.
	 * The result may be a shared instance.
	 * 
	 * @param type
	 *            {@code non-null;} type of the exception
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opMoveException(TypeBearer type) {
		return new Rop(RegOps.MOVE_EXCEPTION, type.getType(),
				StdTypeList.EMPTY, (String) null);
	}

	/**
	 * Returns the appropriate {@code move-result} rop for the given type. The
	 * result may be a shared instance.
	 * 
	 * @param type
	 *            {@code non-null;} type of the parameter
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opMoveResult(TypeBearer type) {
		return new Rop(RegOps.MOVE_RESULT, type.getType(), StdTypeList.EMPTY,
				(String) null);
	}

	/**
	 * Returns the appropriate {@code move-result-pseudo} rop for the given
	 * type. The result may be a shared instance.
	 * 
	 * @param type
	 *            {@code non-null;} type of the parameter
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opMoveResultPseudo(TypeBearer type) {
		return new Rop(RegOps.MOVE_RESULT_PSEUDO, type.getType(),
				StdTypeList.EMPTY, (String) null);
	}

	/**
	 * Returns the appropriate {@code const} rop for the given type. The result
	 * is a shared instance.
	 * 
	 * @param type
	 *            {@code non-null;} type of the constant
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opConst(TypeBearer type) {
		if (type.getType() == Type.KNOWN_NULL) {
			return CONST_OBJECT_NOTHROW;
		}

		switch (type.getBasicFrameType()) {
		case Type.BT_INT:
			return CONST_INT;
		case Type.BT_LONG:
			return CONST_LONG;
		case Type.BT_FLOAT:
			return CONST_FLOAT;
		case Type.BT_DOUBLE:
			return CONST_DOUBLE;
		case Type.BT_OBJECT:
			return CONST_OBJECT;
		}

		return throwBadType(type);
	}

	/**
	 * Returns the appropriate {@code if-eq} rop for the given sources. The
	 * result is a shared instance.
	 * 
	 * @param types
	 *            {@code non-null;} source types
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opIfEq(TypeList types) {
		return pickIf(types, IF_EQZ_INT, IF_EQZ_OBJECT, IF_EQ_INT, IF_EQ_OBJECT);
	}

	/**
	 * Returns the appropriate {@code if-ne} rop for the given sources. The
	 * result is a shared instance.
	 * 
	 * @param types
	 *            {@code non-null;} source types
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opIfNe(TypeList types) {
		return pickIf(types, IF_NEZ_INT, IF_NEZ_OBJECT, IF_NE_INT, IF_NE_OBJECT);
	}

	/**
	 * Returns the appropriate {@code if-lt} rop for the given sources. The
	 * result is a shared instance.
	 * 
	 * @param types
	 *            {@code non-null;} source types
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opIfLt(TypeList types) {
		return pickIf(types, IF_LTZ_INT, null, IF_LT_INT, null);
	}

	/**
	 * Returns the appropriate {@code if-ge} rop for the given sources. The
	 * result is a shared instance.
	 * 
	 * @param types
	 *            {@code non-null;} source types
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opIfGe(TypeList types) {
		return pickIf(types, IF_GEZ_INT, null, IF_GE_INT, null);
	}

	/**
	 * Returns the appropriate {@code if-gt} rop for the given sources. The
	 * result is a shared instance.
	 * 
	 * @param types
	 *            {@code non-null;} source types
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opIfGt(TypeList types) {
		return pickIf(types, IF_GTZ_INT, null, IF_GT_INT, null);
	}

	/**
	 * Returns the appropriate {@code if-le} rop for the given sources. The
	 * result is a shared instance.
	 * 
	 * @param types
	 *            {@code non-null;} source types
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opIfLe(TypeList types) {
		return pickIf(types, IF_LEZ_INT, null, IF_LE_INT, null);
	}

	/**
	 * Helper for all the {@code if*}-related methods, which checks types and
	 * picks one of the four variants, throwing if there's a problem.
	 * 
	 * @param types
	 *            {@code non-null;} the types
	 * @param intZ
	 *            {@code non-null;} the int-to-0 comparison
	 * @param objZ
	 *            {@code null-ok;} the object-to-null comparison
	 * @param intInt
	 *            {@code non-null;} the int-to-int comparison
	 * @param objObj
	 *            {@code non-null;} the object-to-object comparison
	 * @return {@code non-null;} the appropriate instance
	 */
	private static Rop pickIf(TypeList types, Rop intZ, Rop objZ, Rop intInt,
			Rop objObj) {
		switch (types.size()) {
		case 1: {
			switch (types.getType(0).getBasicFrameType()) {
			case Type.BT_INT: {
				return intZ;
			}
			case Type.BT_OBJECT: {
				if (objZ != null) {
					return objZ;
				}
			}
			}
			break;
		}
		case 2: {
			int bt = types.getType(0).getBasicFrameType();
			if (bt == types.getType(1).getBasicFrameType()) {
				switch (bt) {
				case Type.BT_INT: {
					return intInt;
				}
				case Type.BT_OBJECT: {
					if (objObj != null) {
						return objObj;
					}
				}
				}
			}
			break;
		}
		}

		return throwBadTypes(types);
	}

	/**
	 * Returns the appropriate {@code add} rop for the given types. The result
	 * is a shared instance.
	 * 
	 * @param types
	 *            {@code non-null;} types of the sources
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opAdd(TypeList types) {
		return pickBinaryOp(types, ADD_CONST_INT, ADD_CONST_LONG,
				ADD_CONST_FLOAT, ADD_CONST_DOUBLE, ADD_INT, ADD_LONG,
				ADD_FLOAT, ADD_DOUBLE);
	}

	/**
	 * Returns the appropriate {@code sub} rop for the given types. The result
	 * is a shared instance.
	 * 
	 * @param types
	 *            {@code non-null;} types of the sources
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opSub(TypeList types) {
		return pickBinaryOp(types, SUB_CONST_INT, SUB_CONST_LONG,
				SUB_CONST_FLOAT, SUB_CONST_DOUBLE, SUB_INT, SUB_LONG,
				SUB_FLOAT, SUB_DOUBLE);
	}

	/**
	 * Returns the appropriate {@code mul} rop for the given types. The result
	 * is a shared instance.
	 * 
	 * @param types
	 *            {@code non-null;} types of the sources
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opMul(TypeList types) {
		return pickBinaryOp(types, MUL_CONST_INT, MUL_CONST_LONG,
				MUL_CONST_FLOAT, MUL_CONST_DOUBLE, MUL_INT, MUL_LONG,
				MUL_FLOAT, MUL_DOUBLE);
	}

	/**
	 * Returns the appropriate {@code div} rop for the given types. The result
	 * is a shared instance.
	 * 
	 * @param types
	 *            {@code non-null;} types of the sources
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opDiv(TypeList types) {
		return pickBinaryOp(types, DIV_CONST_INT, DIV_CONST_LONG,
				DIV_CONST_FLOAT, DIV_CONST_DOUBLE, DIV_INT, DIV_LONG,
				DIV_FLOAT, DIV_DOUBLE);
	}

	/**
	 * Returns the appropriate {@code rem} rop for the given types. The result
	 * is a shared instance.
	 * 
	 * @param types
	 *            {@code non-null;} types of the sources
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opRem(TypeList types) {
		return pickBinaryOp(types, REM_CONST_INT, REM_CONST_LONG,
				REM_CONST_FLOAT, REM_CONST_DOUBLE, REM_INT, REM_LONG,
				REM_FLOAT, REM_DOUBLE);
	}

	/**
	 * Returns the appropriate {@code and} rop for the given types. The result
	 * is a shared instance.
	 * 
	 * @param types
	 *            {@code non-null;} types of the sources
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opAnd(TypeList types) {
		return pickBinaryOp(types, AND_CONST_INT, AND_CONST_LONG, null, null,
				AND_INT, AND_LONG, null, null);
	}

	/**
	 * Returns the appropriate {@code or} rop for the given types. The result is
	 * a shared instance.
	 * 
	 * @param types
	 *            {@code non-null;} types of the sources
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opOr(TypeList types) {
		return pickBinaryOp(types, OR_CONST_INT, OR_CONST_LONG, null, null,
				OR_INT, OR_LONG, null, null);
	}

	/**
	 * Returns the appropriate {@code xor} rop for the given types. The result
	 * is a shared instance.
	 * 
	 * @param types
	 *            {@code non-null;} types of the sources
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opXor(TypeList types) {
		return pickBinaryOp(types, XOR_CONST_INT, XOR_CONST_LONG, null, null,
				XOR_INT, XOR_LONG, null, null);
	}

	/**
	 * Returns the appropriate {@code shl} rop for the given types. The result
	 * is a shared instance.
	 * 
	 * @param types
	 *            {@code non-null;} types of the sources
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opShl(TypeList types) {
		return pickBinaryOp(types, SHL_CONST_INT, SHL_CONST_LONG, null, null,
				SHL_INT, SHL_LONG, null, null);
	}

	/**
	 * Returns the appropriate {@code shr} rop for the given types. The result
	 * is a shared instance.
	 * 
	 * @param types
	 *            {@code non-null;} types of the sources
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opShr(TypeList types) {
		return pickBinaryOp(types, SHR_CONST_INT, SHR_CONST_LONG, null, null,
				SHR_INT, SHR_LONG, null, null);
	}

	/**
	 * Returns the appropriate {@code ushr} rop for the given types. The result
	 * is a shared instance.
	 * 
	 * @param types
	 *            {@code non-null;} types of the sources
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opUshr(TypeList types) {
		return pickBinaryOp(types, USHR_CONST_INT, USHR_CONST_LONG, null, null,
				USHR_INT, USHR_LONG, null, null);
	}

	/**
	 * Returns the appropriate binary arithmetic rop for the given type and
	 * arguments. The result is a shared instance.
	 * 
	 * @param types
	 *            {@code non-null;} sources of the operation
	 * @param int1
	 *            {@code non-null;} the int-to-constant rop
	 * @param long1
	 *            {@code non-null;} the long-to-constant rop
	 * @param float1
	 *            {@code null-ok;} the float-to-constant rop, if any
	 * @param double1
	 *            {@code null-ok;} the double-to-constant rop, if any
	 * @param int2
	 *            {@code non-null;} the int-to-int rop
	 * @param long2
	 *            {@code non-null;} the long-to-long or long-to-int rop
	 * @param float2
	 *            {@code null-ok;} the float-to-float rop, if any
	 * @param double2
	 *            {@code null-ok;} the double-to-double rop, if any
	 * @return {@code non-null;} an appropriate instance
	 */
	private static Rop pickBinaryOp(TypeList types, Rop int1, Rop long1,
			Rop float1, Rop double1, Rop int2, Rop long2, Rop float2,
			Rop double2) {
		int bt1 = types.getType(0).getBasicFrameType();
		Rop result = null;

		switch (types.size()) {
		case 1: {
			switch (bt1) {
			case Type.BT_INT:
				return int1;
			case Type.BT_LONG:
				return long1;
			case Type.BT_FLOAT:
				result = float1;
				break;
			case Type.BT_DOUBLE:
				result = double1;
				break;
			}
			break;
		}
		case 2: {
			switch (bt1) {
			case Type.BT_INT:
				return int2;
			case Type.BT_LONG:
				return long2;
			case Type.BT_FLOAT:
				result = float2;
				break;
			case Type.BT_DOUBLE:
				result = double2;
				break;
			}
			break;
		}
		}

		if (result == null) {
			return throwBadTypes(types);
		}

		return result;
	}

	/**
	 * Returns the appropriate {@code neg} rop for the given type. The result is
	 * a shared instance.
	 * 
	 * @param type
	 *            {@code non-null;} type of value being operated on
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opNeg(TypeBearer type) {
		switch (type.getBasicFrameType()) {
		case Type.BT_INT:
			return NEG_INT;
		case Type.BT_LONG:
			return NEG_LONG;
		case Type.BT_FLOAT:
			return NEG_FLOAT;
		case Type.BT_DOUBLE:
			return NEG_DOUBLE;
		}

		return throwBadType(type);
	}

	/**
	 * Returns the appropriate {@code not} rop for the given type. The result is
	 * a shared instance.
	 * 
	 * @param type
	 *            {@code non-null;} type of value being operated on
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opNot(TypeBearer type) {
		switch (type.getBasicFrameType()) {
		case Type.BT_INT:
			return NOT_INT;
		case Type.BT_LONG:
			return NOT_LONG;
		}

		return throwBadType(type);
	}

	/**
	 * Returns the appropriate {@code cmpl} rop for the given type. The result
	 * is a shared instance.
	 * 
	 * @param type
	 *            {@code non-null;} type of value being compared
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opCmpl(TypeBearer type) {
		switch (type.getBasicType()) {
		case Type.BT_LONG:
			return CMPL_LONG;
		case Type.BT_FLOAT:
			return CMPL_FLOAT;
		case Type.BT_DOUBLE:
			return CMPL_DOUBLE;
		}

		return throwBadType(type);
	}

	/**
	 * Returns the appropriate {@code cmpg} rop for the given type. The result
	 * is a shared instance.
	 * 
	 * @param type
	 *            {@code non-null;} type of value being compared
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opCmpg(TypeBearer type) {
		switch (type.getBasicType()) {
		case Type.BT_FLOAT:
			return CMPG_FLOAT;
		case Type.BT_DOUBLE:
			return CMPG_DOUBLE;
		}

		return throwBadType(type);
	}

	/**
	 * Returns the appropriate {@code conv} rop for the given types. The result
	 * is a shared instance.
	 * 
	 * @param dest
	 *            {@code non-null;} target value type
	 * @param source
	 *            {@code non-null;} source value type
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opConv(TypeBearer dest, TypeBearer source) {
		int dbt = dest.getBasicFrameType();
		switch (source.getBasicFrameType()) {
		case Type.BT_INT: {
			switch (dbt) {
			case Type.BT_LONG:
				return CONV_I2L;
			case Type.BT_FLOAT:
				return CONV_I2F;
			case Type.BT_DOUBLE:
				return CONV_I2D;
			default:
				break;
			}
		}
		case Type.BT_LONG: {
			switch (dbt) {
			case Type.BT_INT:
				return CONV_L2I;
			case Type.BT_FLOAT:
				return CONV_L2F;
			case Type.BT_DOUBLE:
				return CONV_L2D;
			default:
				break;
			}
		}
		case Type.BT_FLOAT: {
			switch (dbt) {
			case Type.BT_INT:
				return CONV_F2I;
			case Type.BT_LONG:
				return CONV_F2L;
			case Type.BT_DOUBLE:
				return CONV_F2D;
			default:
				break;
			}
		}
		case Type.BT_DOUBLE: {
			switch (dbt) {
			case Type.BT_INT:
				return CONV_D2I;
			case Type.BT_LONG:
				return CONV_D2L;
			case Type.BT_FLOAT:
				return CONV_D2F;
			default:
				break;
			}
		}
		}

		return throwBadTypes(StdTypeList.make(dest.getType(), source.getType()));
	}

	/**
	 * Returns the appropriate {@code return} rop for the given type. The result
	 * is a shared instance.
	 * 
	 * @param type
	 *            {@code non-null;} type of value being returned
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opReturn(TypeBearer type) {
		switch (type.getBasicFrameType()) {
		case Type.BT_INT:
			return RETURN_INT;
		case Type.BT_LONG:
			return RETURN_LONG;
		case Type.BT_FLOAT:
			return RETURN_FLOAT;
		case Type.BT_DOUBLE:
			return RETURN_DOUBLE;
		case Type.BT_OBJECT:
			return RETURN_OBJECT;
		case Type.BT_VOID:
			return RETURN_VOID;
		}

		return throwBadType(type);
	}

	/**
	 * Returns the appropriate {@code aget} rop for the given type. The result
	 * is a shared instance.
	 * 
	 * @param type
	 *            {@code non-null;} element type of array being accessed
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opAget(TypeBearer type) {
		switch (type.getBasicType()) {
		case Type.BT_INT:
			return AGET_INT;
		case Type.BT_LONG:
			return AGET_LONG;
		case Type.BT_FLOAT:
			return AGET_FLOAT;
		case Type.BT_DOUBLE:
			return AGET_DOUBLE;
		case Type.BT_OBJECT:
			return AGET_OBJECT;
		case Type.BT_BOOLEAN:
			return AGET_BOOLEAN;
		case Type.BT_BYTE:
			return AGET_BYTE;
		case Type.BT_CHAR:
			return AGET_CHAR;
		case Type.BT_SHORT:
			return AGET_SHORT;
		}

		return throwBadType(type);
	}

	/**
	 * Returns the appropriate {@code aput} rop for the given type. The result
	 * is a shared instance.
	 * 
	 * @param type
	 *            {@code non-null;} element type of array being accessed
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opAput(TypeBearer type) {
		switch (type.getBasicType()) {
		case Type.BT_INT:
			return APUT_INT;
		case Type.BT_LONG:
			return APUT_LONG;
		case Type.BT_FLOAT:
			return APUT_FLOAT;
		case Type.BT_DOUBLE:
			return APUT_DOUBLE;
		case Type.BT_OBJECT:
			return APUT_OBJECT;
		case Type.BT_BOOLEAN:
			return APUT_BOOLEAN;
		case Type.BT_BYTE:
			return APUT_BYTE;
		case Type.BT_CHAR:
			return APUT_CHAR;
		case Type.BT_SHORT:
			return APUT_SHORT;
		}

		return throwBadType(type);
	}

	/**
	 * Returns the appropriate {@code new-array} rop for the given type. The
	 * result is a shared instance.
	 * 
	 * @param arrayType
	 *            {@code non-null;} array type of array being created
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opNewArray(TypeBearer arrayType) {
		Type type = arrayType.getType();
		Type elementType = type.getComponentType();

		switch (elementType.getBasicType()) {
		case Type.BT_INT:
			return NEW_ARRAY_INT;
		case Type.BT_LONG:
			return NEW_ARRAY_LONG;
		case Type.BT_FLOAT:
			return NEW_ARRAY_FLOAT;
		case Type.BT_DOUBLE:
			return NEW_ARRAY_DOUBLE;
		case Type.BT_BOOLEAN:
			return NEW_ARRAY_BOOLEAN;
		case Type.BT_BYTE:
			return NEW_ARRAY_BYTE;
		case Type.BT_CHAR:
			return NEW_ARRAY_CHAR;
		case Type.BT_SHORT:
			return NEW_ARRAY_SHORT;
		case Type.BT_OBJECT: {
			return new Rop(RegOps.NEW_ARRAY, type, StdTypeList.INT,
					Exceptions.LIST_Error_NegativeArraySizeException,
					"new-array-object");
		}
		}

		return throwBadType(type);
	}

	/**
	 * Returns the appropriate {@code filled-new-array} rop for the given type.
	 * The result may be a shared instance.
	 * 
	 * @param arrayType
	 *            {@code non-null;} type of array being created
	 * @param count
	 *            {@code >= 0;} number of elements that the array should have
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opFilledNewArray(TypeBearer arrayType, int count) {
		Type type = arrayType.getType();
		Type elementType = type.getComponentType();

		if (elementType.isCategory2()) {
			return throwBadType(arrayType);
		}

		if (count < 0) {
			throw new IllegalArgumentException("count < 0");
		}

		StdTypeList sourceTypes = new StdTypeList(count);

		for (int i = 0; i < count; i++) {
			sourceTypes.set(i, elementType);
		}

		// Note: The resulting rop is considered call-like.
		return new Rop(RegOps.FILLED_NEW_ARRAY, sourceTypes,
				Exceptions.LIST_Error);
	}

	/**
	 * Returns the appropriate {@code get-field} rop for the given type. The
	 * result is a shared instance.
	 * 
	 * @param type
	 *            {@code non-null;} type of the field in question
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opGetField(TypeBearer type) {
		switch (type.getBasicType()) {
		case Type.BT_INT:
			return GET_FIELD_INT;
		case Type.BT_LONG:
			return GET_FIELD_LONG;
		case Type.BT_FLOAT:
			return GET_FIELD_FLOAT;
		case Type.BT_DOUBLE:
			return GET_FIELD_DOUBLE;
		case Type.BT_OBJECT:
			return GET_FIELD_OBJECT;
		case Type.BT_BOOLEAN:
			return GET_FIELD_BOOLEAN;
		case Type.BT_BYTE:
			return GET_FIELD_BYTE;
		case Type.BT_CHAR:
			return GET_FIELD_CHAR;
		case Type.BT_SHORT:
			return GET_FIELD_SHORT;
		}

		return throwBadType(type);
	}

	/**
	 * Returns the appropriate {@code put-field} rop for the given type. The
	 * result is a shared instance.
	 * 
	 * @param type
	 *            {@code non-null;} type of the field in question
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opPutField(TypeBearer type) {
		switch (type.getBasicType()) {
		case Type.BT_INT:
			return PUT_FIELD_INT;
		case Type.BT_LONG:
			return PUT_FIELD_LONG;
		case Type.BT_FLOAT:
			return PUT_FIELD_FLOAT;
		case Type.BT_DOUBLE:
			return PUT_FIELD_DOUBLE;
		case Type.BT_OBJECT:
			return PUT_FIELD_OBJECT;
		case Type.BT_BOOLEAN:
			return PUT_FIELD_BOOLEAN;
		case Type.BT_BYTE:
			return PUT_FIELD_BYTE;
		case Type.BT_CHAR:
			return PUT_FIELD_CHAR;
		case Type.BT_SHORT:
			return PUT_FIELD_SHORT;
		}

		return throwBadType(type);
	}

	/**
	 * Returns the appropriate {@code get-static} rop for the given type. The
	 * result is a shared instance.
	 * 
	 * @param type
	 *            {@code non-null;} type of the field in question
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opGetStatic(TypeBearer type) {
		switch (type.getBasicType()) {
		case Type.BT_INT:
			return GET_STATIC_INT;
		case Type.BT_LONG:
			return GET_STATIC_LONG;
		case Type.BT_FLOAT:
			return GET_STATIC_FLOAT;
		case Type.BT_DOUBLE:
			return GET_STATIC_DOUBLE;
		case Type.BT_OBJECT:
			return GET_STATIC_OBJECT;
		case Type.BT_BOOLEAN:
			return GET_STATIC_BOOLEAN;
		case Type.BT_BYTE:
			return GET_STATIC_BYTE;
		case Type.BT_CHAR:
			return GET_STATIC_CHAR;
		case Type.BT_SHORT:
			return GET_STATIC_SHORT;
		}

		return throwBadType(type);
	}

	/**
	 * Returns the appropriate {@code put-static} rop for the given type. The
	 * result is a shared instance.
	 * 
	 * @param type
	 *            {@code non-null;} type of the field in question
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opPutStatic(TypeBearer type) {
		switch (type.getBasicType()) {
		case Type.BT_INT:
			return PUT_STATIC_INT;
		case Type.BT_LONG:
			return PUT_STATIC_LONG;
		case Type.BT_FLOAT:
			return PUT_STATIC_FLOAT;
		case Type.BT_DOUBLE:
			return PUT_STATIC_DOUBLE;
		case Type.BT_OBJECT:
			return PUT_STATIC_OBJECT;
		case Type.BT_BOOLEAN:
			return PUT_STATIC_BOOLEAN;
		case Type.BT_BYTE:
			return PUT_STATIC_BYTE;
		case Type.BT_CHAR:
			return PUT_STATIC_CHAR;
		case Type.BT_SHORT:
			return PUT_STATIC_SHORT;
		}

		return throwBadType(type);
	}

	/**
	 * Returns the appropriate {@code invoke-static} rop for the given type. The
	 * result is typically a newly-allocated instance.
	 * 
	 * @param meth
	 *            {@code non-null;} descriptor of the method
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opInvokeStatic(Prototype meth) {
		return new Rop(RegOps.INVOKE_STATIC, meth.getParameterFrameTypes(),
				StdTypeList.THROWABLE);
	}

	/**
	 * Returns the appropriate {@code invoke-virtual} rop for the given type.
	 * The result is typically a newly-allocated instance.
	 * 
	 * @param meth
	 *            {@code non-null;} descriptor of the method, including the
	 *            {@code this} parameter
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opInvokeVirtual(Prototype meth) {
		return new Rop(RegOps.INVOKE_VIRTUAL, meth.getParameterFrameTypes(),
				StdTypeList.THROWABLE);
	}

	/**
	 * Returns the appropriate {@code invoke-super} rop for the given type. The
	 * result is typically a newly-allocated instance.
	 * 
	 * @param meth
	 *            {@code non-null;} descriptor of the method, including the
	 *            {@code this} parameter
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opInvokeSuper(Prototype meth) {
		return new Rop(RegOps.INVOKE_SUPER, meth.getParameterFrameTypes(),
				StdTypeList.THROWABLE);
	}

	/**
	 * Returns the appropriate {@code invoke-direct} rop for the given type. The
	 * result is typically a newly-allocated instance.
	 * 
	 * @param meth
	 *            {@code non-null;} descriptor of the method, including the
	 *            {@code this} parameter
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opInvokeDirect(Prototype meth) {
		return new Rop(RegOps.INVOKE_DIRECT, meth.getParameterFrameTypes(),
				StdTypeList.THROWABLE);
	}

	/**
	 * Returns the appropriate {@code invoke-interface} rop for the given type.
	 * The result is typically a newly-allocated instance.
	 * 
	 * @param meth
	 *            {@code non-null;} descriptor of the method, including the
	 *            {@code this} parameter
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opInvokeInterface(Prototype meth) {
		return new Rop(RegOps.INVOKE_INTERFACE, meth.getParameterFrameTypes(),
				StdTypeList.THROWABLE);
	}

	/**
	 * Returns the appropriate {@code mark-local} rop for the given type. The
	 * result is a shared instance.
	 * 
	 * @param type
	 *            {@code non-null;} type of value being marked
	 * @return {@code non-null;} an appropriate instance
	 */
	public static Rop opMarkLocal(TypeBearer type) {
		switch (type.getBasicFrameType()) {
		case Type.BT_INT:
			return MARK_LOCAL_INT;
		case Type.BT_LONG:
			return MARK_LOCAL_LONG;
		case Type.BT_FLOAT:
			return MARK_LOCAL_FLOAT;
		case Type.BT_DOUBLE:
			return MARK_LOCAL_DOUBLE;
		case Type.BT_OBJECT:
			return MARK_LOCAL_OBJECT;
		}

		return throwBadType(type);
	}

	/**
	 * This class is uninstantiable.
	 */
	private Rops() {
		// This space intentionally left blank.
	}

	/**
	 * Throws the right exception to complain about a bogus type.
	 * 
	 * @param type
	 *            {@code non-null;} the bad type
	 * @return never
	 */
	private static Rop throwBadType(TypeBearer type) {
		throw new IllegalArgumentException("bad type: " + type);
	}

	/**
	 * Throws the right exception to complain about a bogus list of types.
	 * 
	 * @param types
	 *            {@code non-null;} the bad types
	 * @return never
	 */
	private static Rop throwBadTypes(TypeList types) {
		throw new IllegalArgumentException("bad types: " + types);
	}
}
